/**
 * @author nttdocomo
 */
define(function(require) {
	require("./text");
	require("../../views/markup");
	require("../../views/base");
	aries.klass("aries.form.field.Trigger", aries.form.field.Text.extend({
		childEls : [
		/**
		 * @property {Ext.Element} triggerWrap
		 * A reference to the `TABLE` element which encapsulates the input field and all trigger button(s). Only set after the field has been rendered.
		 */'triggerWrap', 'triggerEl'],
		/**
		 * @cfg {String} [triggerBaseCls='x-form-trigger']
		 * The base CSS class that is always added to the trigger button. The {@link #triggerCls} will be appended in
		 * addition to this class.
		 */
		triggerBaseCls : aries.baseCSSPrefix + 'form-trigger',
		/**
		 * @cfg {String} [triggerWrapCls='x-form-trigger-wrap']
		 * The CSS class that is added to the div wrapping the trigger button(s).
		 */
		triggerWrapCls : aries.baseCSSPrefix + 'form-trigger-wrap',
		// private
		triggerIndexRe : /trigger-index-(\d+)/,

		initialize : function() {
			this.wrapFocusCls = this.triggerWrapCls + '-focus';
			aries.form.field.Text.prototype.initialize.apply(this, arguments);
		},
		getSubTplMarkup : function() {
			var field = aries.form.field.Text.prototype.getSubTplMarkup.apply(this, arguments);
			return '<div id="' + this.id + '-triggerWrap" class="' + aries.baseCSSPrefix + 'form-trigger-wrap input-append" cellpadding="0" cellspacing="0">' + '<div id="' + this.cid + '-inputCell" class="' + aries.baseCSSPrefix + 'form-trigger-input-cell">' + field + '' + this.getTriggerMarkup() + '</div></div>';
		},

		getSubTplData : function() {
			var data = aries.form.field.Text.prototype.getSubTplData.apply(this, arguments), readOnly = this.readOnly === true, editable = this.editable !== false;

			return $.extend(data, {
				editableCls : (readOnly || !editable) ? ' ' + aries.baseCSSPrefix + 'trigger-noedit' : '',
				readOnly : !editable || readOnly
			});
		},

		getLabelableRenderData : function() {
			var me = this, triggerWrapCls = this.triggerWrapCls, result = aries.form.field.Text.prototype.getLabelableRenderData.apply(this, arguments);

			return $.extend(result, {
				triggerWrapCls : triggerWrapCls,
				triggerMarkup : this.getTriggerMarkup()
			});
		},

		getTriggerMarkup : function() {
			var i = 0, hideTrigger = (this.readOnly || this.hideTrigger), triggerCls, triggerBaseCls = this.triggerBaseCls, triggerConfigs = [], triggerMarkups = [];

			// TODO this trigger<n>Cls API design doesn't feel clean, especially where it butts up against the
			// single triggerCls config. Should rethink this, perhaps something more structured like a list of
			// trigger config objects that hold cls, handler, etc.
			// triggerCls is a synonym for trigger1Cls, so copy it.
			if (!this.trigger1Cls) {
				this.trigger1Cls = this.triggerCls;
			}

			// Create as many trigger elements as we have trigger<n>Cls configs, but always at least one
			for ( i = 0; ( triggerCls = this['trigger' + (i + 1) + 'Cls']) || i < 1; i++) {
				triggerConfigs.push({
					tagName : "span",
					attrs : {
						id : this.id + '-triggerEl',
						class : [aries.baseCSSPrefix + 'trigger-index-' + i, 'btn dropdown-toggle', triggerBaseCls].join(" "),
						valign : 'top'/*,
						 style : 'width:' + this.triggerWidth + ( hideTrigger ? 'px;display:none' : 'px')*/
					},
					content : {
						attrs : {
							class : 'caret', //[aries.baseCSSPrefix + 'trigger-index-' + i, triggerBaseCls, triggerCls].join(' '),
							role : 'button'
						}
					}
				});
			}
			triggerConfigs[i - 1].content.className += ' ' + triggerBaseCls + '-last';
			return aries.views.Markup.prototype.markup(triggerConfigs);
			/*for (var k = 0; k < triggerConfigs.length; k++) {
			 triggerMarkups.push((new (aries.views.Base.extend({
			 className : [aries.baseCSSPrefix + 'trigger-index-' + i, triggerBaseCls, triggerCls].join(' '),
			 attributes: {
			 role : 'button'
			 }
			 }))).html());
			 }
			 return triggerMarkups.join("");*/
		},

		// private
		initTrigger : function() {
			var me = this, triggerWrap = me.triggerWrap, triggerEl = me.triggerEl, disableCheck = me.disableCheck, els, eLen, el, e, idx;

			if (me.repeatTriggerClick) {
				me.triggerRepeater = new Ext.util.ClickRepeater(triggerWrap, {
					preventDefault : true,
					handler : me.onTriggerWrapClick,
					listeners : {
						mouseup : me.onTriggerWrapMousup,
						scope : me
					},
					scope : me
				});
			} else {
				triggerWrap.on({
					'click' : _.bind(me.onTriggerWrapClick, me),
					'mouseup' : _.bind(me.onTriggerWrapMousup, me)
				})
				/*me.mon(triggerWrap, {
				 click : me.onTriggerWrapClick,
				 mouseup : me.onTriggerWrapMousup,
				 scope : me
				 });*/
			}

			//triggerEl.setVisibilityMode(Ext.Element.DISPLAY);
			triggerEl.addClsOnOver(me.triggerBaseCls + '-over', disableCheck, me);

			els = triggerEl;
			eLen = els.length;

			els.each(function(idx) {
				$(this).addClsOnOver(me['trigger' + (idx) + 'Cls'] + '-over', disableCheck, me).addClsOnClick(me['trigger' + (idx) + 'Cls'] + '-click', disableCheck, me);
				//$(this).addClsOnClick(me['trigger' + (idx) + 'Cls'] + '-click', disableCheck, me);
			})
			/*for ( e = 0; e < eLen; e++) {
			 el = els[e];
			 idx = e + 1;
			 el.addClsOnOver(me['trigger' + (idx) + 'Cls'] + '-over', disableCheck, me);
			 el.addClsOnClick(me['trigger' + (idx) + 'Cls'] + '-click', disableCheck, me);
			 }*/

			triggerEl.addClsOnClick(me.triggerBaseCls + '-click', disableCheck, me);

		},

		// private
		mimicBlur : function(e) {
			if (!this.isDestroyed && !this.bodyEl.find($(e.target)).length && this.validateBlur(e)) {
				this.triggerBlur(e);
			}
		},

		// private
		onFocus : function() {
			var me = this;
			aries.form.field.Text.prototype.onFocus.apply(this, arguments);
			if (!me.mimicing) {
				me.bodyEl.addClass(me.wrapFocusCls);
				me.mimicing = true;
				me.doc.on('mousedown', _.bind(me.mimicBlur, me)/*, {
				 delay : 10
				 }*/);
				if (me.monitorTab) {
					me.on('specialkey', me.checkTab, me);
				}
			}
		},

		onRender : function() {
			var me = this;

			aries.form.field.Text.prototype.onRender.apply(this, arguments);

			me.doc = $(document);
			me.initTrigger();
			//me.triggerEl.unselectable();
		},

		// private
		// process clicks upon triggers.
		// determine which trigger index, and dispatch to the appropriate click handler
		onTriggerWrapClick : function() {
			var me = this, targetEl, match, triggerClickMethod, event;

			event = arguments[me.triggerRepeater ? 1 : 0];
			if (event && !me.readOnly && !me.disabled) {
				targetEl = $(event.target).closest('.' + me.triggerBaseCls);
				match = targetEl.length && targetEl.attr("class").match(me.triggerIndexRe);

				if (match) {
					triggerClickMethod = me['onTrigger' + (parseInt(match[1], 10) + 1) + 'Click'] || me.onTriggerClick;
					if (triggerClickMethod) {
						triggerClickMethod.call(me, event);
					}
				}
			}
		},

		// private
		// Handle trigger mouse up gesture. To be implemented in subclasses.
		// Currently the Spinner subclass refocuses the input element upon end of spin.
		onTriggerWrapMousup : aries.emptyFn,

		// private
		triggerBlur : function(e) {
			var me = this;
			me.mimicing = false;
			me.doc.off('mousedown', me.mimicBlur);
			if (me.monitorTab && me.inputEl) {
				me.un('specialkey', me.checkTab, me);
			}
			aries.form.field.Text.prototype.onBlur.call(me, e);
			if (me.bodyEl) {
				me.bodyEl.removeClass(me.wrapFocusCls);
			}
		},

		// private
		// This should be overridden by any subclass that needs to check whether or not the field can be blurred.
		validateBlur : function(e) {
			return true;
		}
	}));
})
